
#include "port/GFX_ST7735.h"

namespace GFX {

// Some register settings
#define ST7735_MADCTL_BGR 0x08
#define ST7735_MADCTL_MH  0x04

#define ST7735_FRMCTR1 0xB1
#define ST7735_FRMCTR2 0xB2
#define ST7735_FRMCTR3 0xB3
#define ST7735_INVCTR  0xB4
#define ST7735_DISSET5 0xB6

#define ST7735_PWCTR1 0xC0
#define ST7735_PWCTR2 0xC1
#define ST7735_PWCTR3 0xC2
#define ST7735_PWCTR4 0xC3
#define ST7735_PWCTR5 0xC4
#define ST7735_VMCTR1 0xC5

#define ST7735_PWCTR6 0xFC

#define ST7735_GMCTRP1 0xE0
#define ST7735_GMCTRN1 0xE1

// SCREEN INITIALIZATION ***************************************************

// Rather than a bazillion writecommand() and writedata() calls, screen
// initialization commands and arguments are organized in these tables
// stored in PROGMEM.  The table may look bulky, but that's mostly the
// formatting -- storage-wise this is hundreds of bytes more compact
// than the equivalent code.  Companion function follows.

// clang-format off  
static const uint8_t PROGMEM InitCfg[] = {            // 7735R init, part 1 (red or green tab) 
    ST77XX_SWRESET,   ST_CMD_DELAY, //  1: Software reset, 0 args, w/delay
      150,                          //     150 ms delay
    ST77XX_SLPOUT,    ST_CMD_DELAY, //  2: Out of sleep mode, 0 args, w/delay
      255,                          //     500 ms delay
    ST7735_FRMCTR1, 3,              //  3: Framerate ctrl - normal mode, 3 arg:
      0x01, 0x2C, 0x2D,             //     Rate = fosc/(1x2+40) * (LINE+2C+2D)
    ST7735_FRMCTR2, 3,              //  4: Framerate ctrl - idle mode, 3 args:
      0x01, 0x2C, 0x2D,             //     Rate = fosc/(1x2+40) * (LINE+2C+2D)
    ST7735_FRMCTR3, 6,              //  5: Framerate - partial mode, 6 args:
      0x01, 0x2C, 0x2D,             //     Dot inversion mode
      0x01, 0x2C, 0x2D,             //     Line inversion mode
    ST7735_INVCTR,  1,              //  6: Display inversion ctrl, 1 arg:
      0x07,                         //     No inversion
    ST7735_PWCTR1,  3,              //  7: Power control, 3 args, no delay:
      0xA2,
      0x02,                         //     -4.6V
      0x84,                         //     AUTO mode
    ST7735_PWCTR2,  1,              //  8: Power control, 1 arg, no delay:
      0xC5,                         //     VGH25=2.4C VGSEL=-10 VGH=3 * AVDD
    ST7735_PWCTR3,  2,              //  9: Power control, 2 args, no delay:
      0x0A,                         //     Opamp current small
      0x00,                         //     Boost frequency
    ST7735_PWCTR4,  2,              // 10: Power control, 2 args, no delay:
      0x8A,                         //     BCLK/2,
      0x2A,                         //     opamp current small & medium low
    ST7735_PWCTR5,  2,              // 11: Power control, 2 args, no delay:
      0x8A, 0xEE,
    ST7735_VMCTR1,  1,              // 12: Power control, 1 arg, no delay:
      0x0E,
    ST77XX_INVOFF,  0,              // 13: Don't invert display, no args
    ST77XX_MADCTL,  1,              // 14: Mem access ctl (directions), 1 arg:
      0xC8,                         //     row/col addr, bottom-top refresh
    ST77XX_COLMOD,  1,              // 15: set color mode, 1 arg, no delay:
      0x05 ,                        //     16-bit color
      
    ST7735_GMCTRP1, 16      ,       //  1: Gamma Adjustments (pos. polarity), 16 args + delay:
      0x02, 0x1c, 0x07, 0x12,       //     (Not entirely necessary, but provides
      0x37, 0x32, 0x29, 0x2d,       //      accurate colors)
      0x29, 0x25, 0x2B, 0x39,
      0x00, 0x01, 0x03, 0x10,
    ST7735_GMCTRN1, 16      ,       //  2: Gamma Adjustments (neg. polarity), 16 args + delay:
      0x03, 0x1d, 0x07, 0x06,       //     (Not entirely necessary, but provides
      0x2E, 0x2C, 0x29, 0x2D,       //      accurate colors)
      0x2E, 0x2E, 0x37, 0x3F,
      0x00, 0x00, 0x02, 0x10,
    ST77XX_NORON,     ST_CMD_DELAY, //  3: Normal display on, no args, w/delay
      10,                           //     10 ms delay
    ST77XX_DISPON,    ST_CMD_DELAY, //  4: Main screen turn on, no args w/delay
      100 ,                       //     100 ms delay
       0x00, 0x00 } ;

// clang-format on

GFX_ST7735::GFX_ST7735(GFX_PortBase &lcd, uint8_t options) //
    : GFX_ST77xx(lcd, 128, 160), _bgr(true) {
    if (options == INITR_GREENTAB) {
        _colstart = 2;
        _rowstart = 1;
    } else if ((options == INITR_144GREENTAB) || (options == INITR_HALLOWING)) {
        _height   = ST7735_TFTHEIGHT_128;
        _width    = ST7735_TFTWIDTH_128;
        _colstart = 2;
        _rowstart = 3; // For default rotation 0
    } else if (options == INITR_MINI160x80) {
        _height   = ST7735_TFTWIDTH_80;
        _width    = ST7735_TFTHEIGHT_160;
        _colstart = 24;
        _rowstart = 0;
    } else if (options == INITR_MINI160x80_PLUGIN) {
        _height   = ST7735_TFTWIDTH_80;
        _width    = ST7735_TFTHEIGHT_160;
        _colstart = 26;
        _rowstart = 1;
    }

    HEIGHT  = _height;
    WIDTH   = _width;
    _xstart = _colstart;
    _ystart = _rowstart;
}

GFX_ST7735::GFX_ST7735(GFX_PortBase &lcd, uint16_t w, uint16_t h, bool bgr) //
    : GFX_ST77xx(lcd, w, h), _bgr(bgr) {
    if (w == 128) {
        if (h == 128) {
            _colstart = 2;
            _rowstart = 3; // For default rotation 0
        }
    } else if (w == 80) {
        _colstart = 24;
    } else if (w == 160) {
        _colstart = 26;
        _rowstart = 1;
    }
    _xstart = _colstart;
    _ystart = _rowstart;
}

GFX_ST7735::~GFX_ST7735() {}

void GFX_ST7735::tftInit() { displayInit(InitCfg); }

/**************************************************************************/
/*!
    @brief  Set origin of (0,0) and orientation of TFT display
    @param  m  The index for rotation, from 0-3 inclusive
*/
/**************************************************************************/
void GFX_ST7735::setRotation(uint8_t r) {
    GFX_disRGB::setRotation(r);
    switch (_rotation) {
        case 1:
            r = ST77XX_MADCTL_MY | ST77XX_MADCTL_MV | (_bgr ? ST7735_MADCTL_BGR : ST77XX_MADCTL_RGB);
            break;
        case 2:
            r = (_bgr ? ST7735_MADCTL_BGR : ST77XX_MADCTL_RGB);
            break;
        case 3:
            r = ST77XX_MADCTL_MX | ST77XX_MADCTL_MV | (_bgr ? ST7735_MADCTL_BGR : ST77XX_MADCTL_RGB);
            break;
        default: // case 0:
            r = ST77XX_MADCTL_MX | ST77XX_MADCTL_MY | (_bgr ? ST7735_MADCTL_BGR : ST77XX_MADCTL_RGB);
            break;
    }
    sendC8D8(ST77XX_MADCTL, r);
}

} // namespace GFX
